package com.snb.play.dwebtoon.util;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import android.content.Context;

import com.snb.play.dwebtoon.data.DTO_Artist;
import com.snb.play.dwebtoon.data.DTO_Episode;
import com.snb.play.dwebtoon.data.DTO_EpisodeDatas;
import com.snb.play.dwebtoon.data.DTO_EpisodeImage;
import com.snb.play.dwebtoon.data.DTO_EpisodeToon;
import com.snb.play.dwebtoon.data.DTO_Genre;
import com.snb.play.dwebtoon.data.DTO_WebToon;

public class DBProvider extends Abatis {
	private static final String TAG = DBProvider.class.getSimpleName();

	private static final String DB_NAME = "WEBTOON";
	// private static Class[] DTOCLASSES = { DTO_Artist.class,
	// DTO_Cartoon.class, DTO_Category.class, DTO_Episode.class,
	// DTO_EpisodeDatas.class,
	// DTO_EpisodePage.class, DTO_EpisodeToon.class, DTO_Genre.class,
	// DTO_Page.class, DTO_Result.class, DTO_WebToon.class };
	@SuppressWarnings("rawtypes")
	private static Class[] DTOCLASSES = { DTO_Artist.class, DTO_WebToon.class, DTO_Genre.class, DTO_EpisodeDatas.class, DTO_Episode.class,
			DTO_EpisodeToon.class, DTO_EpisodeImage.class };
	private static final String BASEINITTABLESTRING0 = "CREATE TABLE IF NOT EXISTS ";
	private static final String BASEINITTABLESTRING1 = "( id_num TEXT ";

	public static void initInstance(Context aContext) {
		if (gDbProvider == null) {
			gDbProvider = new DBProvider(aContext);
		}
	}

	public static DBProvider gDbProvider;

	public static synchronized DBProvider getInstance() {
		synchronized (gDbProvider) {
			gDbProvider.begin();
			return gDbProvider;
		}

	}

	private static String getAllDTOTableString() {

		StringBuilder returnString = new StringBuilder();
		for (Class lClass : DTOCLASSES) {

			returnString.append(BASEINITTABLESTRING0);
			returnString.append(lClass.getSimpleName());
			returnString.append(BASEINITTABLESTRING1);
			// PRIMARY KEY AUTOINCREMENT
			for (Field lField : lClass.getDeclaredFields()) {
				if (!lField.getName().equalsIgnoreCase("TAG") && !lField.getName().equalsIgnoreCase("serialVersionUID")) {

					returnString.append(", ");
					if (lField.getName().equalsIgnoreCase("id")) {
						returnString.append(lField.getName());
						returnString.append(" TEXT PRIMARY KEY ");
					} else {
						returnString.append(lField.getName());
						returnString.append(" TEXT");
					}
				}
			}

			returnString.append(") ;");
		}
		return returnString.toString();
	}

	private DBProvider(Context context) {
		super(context, DB_NAME, getAllDTOTableString());
	}

	public static final String _VALUE = "_VALUE_";
	public static final String _TABLE = "_TABLE_";
	public static final String _NAMES = "_NAMES_";
	public static final String _ID = "_ID_";

	public static final String _KEY = "_KEY_";

	String BASEINSERT = "INSERT INTO _TABLE_ ( _NAMES_ ) VALUES ( _VALUE_ )";

	String BASEALLGET = "SELECT * FROM ";
	String BASECOUNT = "SELECT COUNT(*) FROM ";
	String BASEWHERE = " WHERE ";
	String BASEWHERESELECT = "_KEY_ = '_VALUE_'";
	String BASEWHERESELECT_BY_LIKE = "_KEY_ LIKE '%_VALUE_%'";
	String BASEAND = " AND ";
	String BASEOR = " OR ";
	String BASEKEY_VALUE = " _KEY_ = '_VALUE_'";

	public <T> ArrayList<T> getToons(Object aTargetObject, String where) {
		if (aTargetObject == null)
			return null;

		List<T> lList = executeForBeanList(BASEALLGET + aTargetObject.getClass().getSimpleName() + where, null, aTargetObject.getClass());
		ArrayList<T> ret = new ArrayList<T>();
		ret.addAll(lList);
		return ret;
	}
	
	public <T> ArrayList<T> getToons(Object aTargetObject, boolean aSearchingByAnd) {
		
		if (aTargetObject == null)
			return null;

		boolean isFirst = true;

		StringBuilder lWheres = new StringBuilder();
		for (Field lF : aTargetObject.getClass().getFields()) {
			String lKey = lF.getName();
			String lValue = "";
			try {
				lValue = lF.get(aTargetObject).toString();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (Exception e) {
				// TODO: handle exception
			}
			if (!lKey.equalsIgnoreCase("TAG") && lF.getType().equals(String.class) && lKey != null && lValue != null && lKey.length() > 0
					&& lValue.length() > 0) {
				if (!isFirst) {
					if (aSearchingByAnd)
						lWheres.append(BASEAND);
					else
						lWheres.append(BASEOR);

					lWheres.append(BASEWHERESELECT_BY_LIKE.replace(_KEY, lKey).replace(_VALUE, lValue));
					isFirst = false;
				} else {
					lWheres.append(BASEWHERE);
					lWheres.append(BASEWHERESELECT_BY_LIKE.replace(_KEY, lKey).replace(_VALUE, lValue));
					isFirst = false;
				}
			}
		}
		Logger.printStartTime();
		List<T> lList = executeForBeanList(BASEALLGET + aTargetObject.getClass().getSimpleName() + lWheres.toString(), null, aTargetObject.getClass());
		ArrayList<T> ret = new ArrayList<T>();
		ret.addAll(lList);
		Logger.printEndTime(TAG);
		return ret;
	}

	public <T> ArrayList<T> getAllObjs(Class aTargetClass) {
		List<T> lList = executeForBeanList(BASEALLGET + aTargetClass.getSimpleName(), null, aTargetClass);
		ArrayList<T> ret = new ArrayList<T>();
		ret.addAll(lList);
		return ret;
	}

	// order by 정렬하고 싶은 필드명 asc(오름차순)
	public static final String BASE_ORDERBY_ASC = "order by _ID_ asc";
	public static final String BASE_ORDERBY_DESC = "order by _ID_ desc";

	public Object getObjByID(Object aTargetObject) {
		if (aTargetObject == null)
			return null;
		boolean isFirst = true;

		StringBuilder lWheres = new StringBuilder();
		for (Field lF : aTargetObject.getClass().getFields()) {
			String lKey = lF.getName();
			String lValue = "";
			try {
				lValue = lF.get(aTargetObject).toString();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (Exception e) {
				// TODO: handle exception
			}
			if (lF.getName().indexOf("TAG") < 0 && lF.getType().equals(String.class) && lKey != null && lValue != null && lKey.length() > 0
					&& lValue.length() > 0) {
				if (!isFirst) {
					lWheres.append(BASEAND);
					lWheres.append(BASEWHERESELECT.replace(_KEY, lKey).replace(_VALUE, lValue));
					isFirst = false;
				} else {
					lWheres.append(BASEWHERE);
					lWheres.append(BASEWHERESELECT.replace(_KEY, lKey).replace(_VALUE, lValue));
					isFirst = false;
				}
			}
		}

		aTargetObject = executeForBean(BASEALLGET + aTargetObject.getClass().getSimpleName() + lWheres.toString(), null, aTargetObject.getClass());

		return aTargetObject;
	}

	public <T> ArrayList<T> getAllObjByID(Object aTargetObject) {
		if (aTargetObject == null)
			return null;

		boolean isFirst = true;

		StringBuilder lWheres = new StringBuilder();
		for (Field lF : aTargetObject.getClass().getFields()) {
			String lKey = lF.getName();
			String lValue = "";
			try {
				lValue = lF.get(aTargetObject).toString();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (Exception e) {
				// TODO: handle exception
			}
			if (!lKey.equalsIgnoreCase("TAG") && lF.getType().equals(String.class) && lKey != null && lValue != null && lKey.length() > 0
					&& lValue.length() > 0) {
				if (!isFirst) {
					lWheres.append(BASEAND);
					lWheres.append(BASEWHERESELECT.replace(_KEY, lKey).replace(_VALUE, lValue));
					isFirst = false;
				} else {
					lWheres.append(BASEWHERE);
					lWheres.append(BASEWHERESELECT.replace(_KEY, lKey).replace(_VALUE, lValue));
					isFirst = false;
				}
			}
		}

		List<T> lList = executeForBeanList(BASEALLGET + aTargetObject.getClass().getSimpleName() + lWheres.toString(), null, aTargetObject.getClass());
		ArrayList<T> ret = new ArrayList<T>();
		ret.addAll(lList);
		return ret;
	}

	public int getObjTotalSize(Class aTargetClass) {
		String SIZE = BASECOUNT + aTargetClass.getSimpleName();
		Logger.d(TAG, SIZE);
		return executeForgetSize(SIZE);

	}

	public int getSelectObjTotalSize(Object aTargetObject) {

		if (aTargetObject == null)
			return 0;

		boolean isFirst = true;

		StringBuilder lWheres = new StringBuilder();
		for (Field lF : aTargetObject.getClass().getFields()) {
			String lKey = lF.getName();
			String lValue = "";
			try {
				lValue = lF.get(aTargetObject).toString();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (Exception e) {
				// TODO: handle exception
			}
			if (!lKey.equalsIgnoreCase("TAG") && lF.getType().equals(String.class) && lKey != null && lValue != null && lKey.length() > 0
					&& lValue.length() > 0) {
				if (!isFirst) {
					lWheres.append(BASEAND);
					lWheres.append(BASEWHERESELECT.replace(_KEY, lKey).replace(_VALUE, lValue));
					isFirst = false;
				} else {
					lWheres.append(BASEWHERE);
					lWheres.append(BASEWHERESELECT.replace(_KEY, lKey).replace(_VALUE, lValue));
					isFirst = false;
				}
			}
		}

		String SIZE = BASECOUNT + aTargetObject.getClass().getSimpleName() + lWheres.toString();
		Logger.d(TAG, SIZE);
		return executeForgetSize(SIZE);

	}

	public boolean updateObjById(Object aTargetObject) {

		if (aTargetObject == null)
			return false;

		boolean isFirst = true;

		StringBuilder lKeyValue = new StringBuilder();
		for (Field lF : aTargetObject.getClass().getFields()) {
			String lKey = lF.getName();
			String lValue = "";
			try {
				lValue = lF.get(aTargetObject).toString();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (Exception e) {
				// TODO: handle exception
			}
			if (!lKey.equalsIgnoreCase("TAG") && !lKey.equalsIgnoreCase("id") && lF.getType().equals(String.class) && lKey != null && lValue != null
					&& lKey.length() > 0 && lValue.length() > 0) {
				if (!isFirst) {
					lKeyValue.append(",");
					lKeyValue.append(BASEKEY_VALUE.replace(_KEY, lKey).replace(_VALUE, lValue));
					isFirst = false;
				} else {
					lKeyValue.append(BASEKEY_VALUE.replace(_KEY, lKey).replace(_VALUE, lValue));
					isFirst = false;
				}
			}
		}

		String lID = "";

		int result = 0;
		try {
			lID = (aTargetObject.getClass().getField("id")).get(aTargetObject).toString();
		} catch (Exception e) {
		}

		Logger.d("BUM", BASEUPDATE.replace(_TABLE, aTargetObject.getClass().getSimpleName()).replace(_KEYVALUE, lKeyValue).replace(_ID, lID.trim()));
		if (lID.trim().length() > 0)
			result = DBProvider.getInstance().executeDirectSqlNonClose(
					BASEUPDATE.replace(_TABLE, aTargetObject.getClass().getSimpleName()).replace(_KEYVALUE, lKeyValue).replace(_ID, lID.trim()));
		return result > 0;
	}

	public static final String BASEUPDATE = "UPDATE _TABLE_ SET _KEYVALUE_ WHERE id='_ID_';";

	public static final String _KEYVALUE = "_KEYVALUE_";

	public void deleteObjByID(Object aTargetObject) {
		if (aTargetObject == null)
			return;
		boolean isFirst = true;

		StringBuilder lWheres = new StringBuilder();
		for (Field lF : aTargetObject.getClass().getFields()) {
			String lKey = lF.getName();
			String lValue = "";
			try {
				lValue = lF.get(aTargetObject).toString();
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (Exception e) {
			}
			if (lF.getName().indexOf("TAG") < 0 && lF.getType().equals(String.class) && lKey != null && lValue != null && lKey.length() > 0
					&& lValue.length() > 0) {
				if (!isFirst) {
					lWheres.append(BASEAND);
					lWheres.append(BASEWHERESELECT.replace(_KEY, lKey).replace(_VALUE, lValue));
					isFirst = false;
				} else {
					lWheres.append(BASEWHERE);
					lWheres.append(BASEWHERESELECT.replace(_KEY, lKey).replace(_VALUE, lValue));
					isFirst = false;
				}
			}
		}

		Logger.d(TAG, BASEDELETE + aTargetObject.getClass().getSimpleName() + lWheres.toString());
		aTargetObject = executeForBean(BASEDELETE + aTargetObject.getClass().getSimpleName() + lWheres.toString(), null, aTargetObject.getClass());

	}

	String BASEDELETE = "DELETE FROM ";
}
